//------------------------------------------------------------------------------
// <copyright file="UrlPath.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace System.Configuration {
    using System.Collections;
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Security;
    using System.Text;
    using System.Xml;
    using Microsoft.Win32;

    static internal class UrlPath {
    
        internal static string GetDirectoryOrRootName(string path) {
            string dir;
    
            dir = Path.GetDirectoryName(path);
            if (dir == null) {
                // dir == null if path = "c:\"
                dir = Path.GetPathRoot(path);
            }
    
            return dir;
        }

        //
        // Determine if subdir is equal to or a subdirectory of dir.
        // For example, c:\mydir\subdir is a subdirectory of c:\mydir
        // Account for optional trailing backslashes.
        //
        internal static bool IsEqualOrSubdirectory(string dir, string subdir) {
            if (String.IsNullOrEmpty(dir))
                return true;

            if (String.IsNullOrEmpty(subdir))
                return false;

            //
            // Compare up to but not including trailing backslash
            //
            int lDir = dir.Length;
            if (dir[lDir - 1] == '\\') {
                lDir -= 1;
            }

            int lSubdir = subdir.Length;
            if (subdir[lSubdir - 1] == '\\') {
                lSubdir -= 1;
            }

            if (lSubdir < lDir)
                return false;

            if (String.Compare(dir, 0, subdir, 0, lDir, StringComparison.OrdinalIgnoreCase) != 0)
                return false;

            // Check subdir that character following length of dir is a backslash
            if (lSubdir > lDir && subdir[lDir] != '\\')
                return false;

            return true;
        }

        //
        // NOTE: This function is also present in fx\src\xsp\system\web\util\urlpath.cs
        // Please propagate any changes to that file.
        //
        // Determine if subpath is equal to or a subpath of path.
        // For example, /myapp/foo.aspx is a subpath of /myapp
        // Account for optional trailing slashes.
        //
        internal static bool IsEqualOrSubpath(string path, string subpath) {
            return IsEqualOrSubpathImpl(path, subpath, false);
        }


        //
        // Determine if subpath is a subpath of path, but return
        // false if subpath & path are the same.
        // For example, /myapp/foo.aspx is a subpath of /myapp
        // Account for optional trailing slashes.
        //
        internal static bool IsSubpath(string path, string subpath) {
            return IsEqualOrSubpathImpl(path, subpath, true);
        }
        
        private static bool IsEqualOrSubpathImpl(string path, string subpath, bool excludeEqual) {
            if (String.IsNullOrEmpty(path))
                return true;

            if (String.IsNullOrEmpty(subpath))
                return false;

            //
            // Compare up to but not including trailing slash
            //
            int lPath = path.Length;
            if (path[lPath - 1] == '/') {
                lPath -= 1;
            }

            int lSubpath = subpath.Length;
            if (subpath[lSubpath - 1] == '/') {
                lSubpath -= 1;
            }

            if (lSubpath < lPath)
                return false;

            if (excludeEqual && lSubpath == lPath)
                return false;

            if (String.Compare(path, 0, subpath, 0, lPath, StringComparison.OrdinalIgnoreCase) != 0)
                return false;

            // Check subpath that character following length of path is a slash
            if (lSubpath > lPath && subpath[lPath] != '/')
                return false;

            return true;
        }

        private static bool IsDirectorySeparatorChar(char ch) {
            return (ch == '\\' || ch == '/');
        }

        private static bool IsAbsoluteLocalPhysicalPath(string path) {
            if (path == null || path.Length < 3)
                return false;

            // e.g c:\foo
            return (path[1] == ':' && IsDirectorySeparatorChar(path[2]));
        }

        private static bool IsAbsoluteUNCPhysicalPath(string path) {
            if (path == null || path.Length < 3)
                return false;

            // e.g \\server\share\foo or //server/share/foo
            return (IsDirectorySeparatorChar(path[0]) && IsDirectorySeparatorChar(path[1]));
        }

        const string FILE_URL_LOCAL = "file:///";
        const string FILE_URL_UNC = "file:";

        internal static string ConvertFileNameToUrl(string fileName) {
            string prefix;

            if (IsAbsoluteLocalPhysicalPath(fileName)) {
                prefix = FILE_URL_LOCAL;
            }
            else if (IsAbsoluteUNCPhysicalPath(fileName)) {
                prefix = FILE_URL_UNC;
            }
            else {
                // We should never get here, but if we do we are likely to have
                // serious security problems, so throw an exception rather than simply 
                // asserting.
                throw ExceptionUtil.ParameterInvalid("filename");
            }

            string newFileName = prefix + fileName.Replace('\\', '/');
            return newFileName;
        }
    }
}
